home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / HPACK78S.ZIP / cli.c < prev    next >
C/C++ Source or Header  |  1992-12-02  |  31KB  |  1,088 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                                HPACK CLI Interface                            *
  7. *                              CLI.C  Updated 06/05/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *        Copyright 1989 - 1992  Peter C.Gutmann.  All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #ifdef __MAC__
  22.   #include "defs.h"
  23.   #include "arcdir.h"
  24.   #include "choice.h"
  25.   #include "error.h"
  26.   #include "filesys.h"
  27.   #include "flags.h"
  28.   #include "frontend.h"
  29.   #include "hpacklib.h"
  30.   #include "hpaktext.h"
  31.   #include "system.h"
  32.   #include "wildcard.h"
  33.   #include "crypt.h"
  34.   #include "fastio.h"
  35. #else
  36.   #include "defs.h"
  37.   #include "arcdir.h"
  38.   #include "choice.h"
  39.   #include "error.h"
  40.   #include "filesys.h"
  41.   #include "flags.h"
  42.   #include "frontend.h"
  43.   #include "hpacklib.h"
  44.   #include "system.h"
  45.   #include "wildcard.h"
  46.   #include "crypt/crypt.h"
  47.   #include "io/fastio.h"
  48.   #include "language/hpaktext.h"
  49. #endif /* __MAC__ */
  50.  
  51. /* Prototypes for functions in VIEWFILE.C */
  52.  
  53. void setDateFormat( void );
  54.  
  55. /* Prototypes for functions in SCRIPT.C */
  56.  
  57. void addFilespec( char *fileSpec );
  58. void freeFilespecs( void );
  59. void processListFile( const char *listFileName );
  60.  
  61. /* Prototypes for compression functions */
  62.  
  63. void initPack( const BOOLEAN initAllBuffers );
  64. void endPack( void );
  65.  
  66. /* Prototypes for functions in VIEWFILE.C */
  67.  
  68. void showTotals( void );
  69.  
  70. /* The default match string, which matches all files.  This must be done
  71.    as a static array since if given as a constant string some compilers
  72.    may put it into the code segment which may cause problems when FILESYS.C
  73.    attempts any conversion on it */
  74.  
  75. char WILD_MATCH_ALL[] = "*";
  76.  
  77. /* The following are defined in ARCHIVE.C */
  78.  
  79. extern BOOLEAN overWriteEntry;    /* Whether we overwrite the existing file
  80.                                    entry or add a new one in addFileHeader()
  81.                                    - used by FRESHEN, REPLACE, UPDATE */
  82. #ifdef __MSDOS__
  83.   void ndoc( const char **strPtr );
  84. #endif /* __MSDOS__ */
  85. #ifdef __OS2__
  86.   BOOLEAN queryFilesystemType( char *path );
  87. #endif /* __OS2__ */
  88. #ifdef __MAC__
  89.   #define ARCHIVE_PATH    TRUE
  90.   #define FILE_PATH        FALSE
  91.  
  92.   void setVolumeRef( char *path, const BOOLEAN isArchivePath );
  93.   int stripVolumeName( char *path );
  94. #endif /* __MAC__ */
  95. #ifdef __VMS__
  96.   int translateVMSretVal( const int retVal );
  97. #endif /* __VMS__ */
  98.  
  99. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
  100.  
  101. /* The drive the archive is on (needed for multidisk archives) */
  102.  
  103. extern BYTE archiveDrive;
  104. #endif /* __ATARI__ || __MSDOS__ || __OS2__ */
  105.  
  106. /****************************************************************************
  107. *                                                                            *
  108. *                            Handle Command-line Switches                    *
  109. *                                                                            *
  110. ****************************************************************************/
  111.  
  112. /* Handle the command for the archive.  This can also be done in a switch
  113.    statement; however the compiler probably produces code equivalent to the
  114.    following, and it is far more compact in source form */
  115.  
  116. #define NO_CMDS    9
  117.  
  118. static void doCommand( const char *theCommand )
  119.     {
  120.     int i;
  121.  
  122.     choice = toupper( *theCommand );
  123.     for( i = 0; ( i < NO_CMDS ) && ( "ADFPVXRUT"[ i ] != choice ); i++ );
  124.     if( i == NO_CMDS || theCommand[ 1 ] )
  125.         error( UNKNOWN_COMMAND, theCommand );
  126.     }
  127.  
  128. /* Get a byte as two hex digits - used by several sections of doArg() */
  129.  
  130. #ifdef __MSDOS__
  131.   BYTE getHexByte( char **strPtr );
  132. #else
  133. BYTE getHexByte( char **strPtr )
  134.     {
  135.     char ch;
  136.     BYTE retVal;
  137.  
  138.     retVal = toupper( **strPtr );
  139.     retVal -= ( retVal >= 'A' ) ? 'A' - 10 : '0';
  140.     *strPtr++;
  141.     if( isxdigit( **strPtr ) )
  142.         {
  143.         retVal <<= 4;
  144.         ch = toupper( **strPtr );
  145.         ch -= ( ch >= 'A' ) ? ( 'A' - 10 ) : '0';
  146.         retVal |= ch;
  147.         }
  148.     return( retVal );
  149.     }
  150. #endif /* __MSDOS__ */
  151.  
  152. /* Get all switches and point at the next arg to process */
  153.  
  154. /* Flags used/not used:
  155.    Used:     ABCDEF..I.KLMNO..RSTUVWX.Z
  156.    Not used: ......GH.J.....PQ.......Y. */
  157.  
  158. static void doArg( char *argv[], int *count )
  159.     {
  160.     char *strPtr, ch;
  161.     BYTE lineEndChar;
  162.     int length = 0;
  163.  
  164.     *basePath = '\0';    /* Default is no output directory */
  165.  
  166.     while( TRUE )
  167.         {
  168.         /* Get next arg */
  169.         strPtr = ( char * ) argv[ *count ];
  170.         if( *strPtr != '-' )
  171.             break;
  172.  
  173.         /* Check for '--' as end of arg list */
  174.         if( *++strPtr == '-' )
  175.             {
  176.             /* This was the last arg */
  177.             ( *count )++;
  178.             break;
  179.             }
  180.  
  181.         /* Process individual args */
  182.         while( *strPtr )
  183.             {
  184.             ch = *strPtr++;                /* Avoid toupper() side-effects */
  185.             switch( toupper( ch ) )
  186.                 {
  187.                 case '0':
  188.                     flags |= STORE_ONLY;
  189.                     break;
  190.  
  191.                 case 'A':
  192.                     flags |= STORE_ATTR;
  193.                     break;
  194.  
  195.                 case 'B':
  196.                     /* Copy the argument across */
  197.                     while( *strPtr )
  198.                         {
  199.                         basePath[ length ] = caseConvert( *strPtr );
  200. #if defined( __ATARI__ ) || defined( __OS2__ )
  201.                         if( basePath[ length ] == '\\' )
  202.                             basePath[ length ] = SLASH;
  203. #endif /* __ATARI__ || __OS2__ */
  204.                         strPtr++;
  205.                         if( ++length >= MAX_PATH - 1 )
  206.                             error( PATH_s__TOO_LONG, basePath );
  207.                         }
  208.                     basePath[ length ] = '\0';
  209.  
  210.                     /* Append SLASH if necessary */
  211. #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __ATARI__ ) || \
  212.     defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __OS2__ ) || \
  213.     defined( __VMS__ )
  214.                     if( length && ( ch = basePath[ length - 1 ] ) != SLASH && \
  215.                                                                ch != ':' )
  216. #else
  217.                     if( length && ( ch = basePath[ length - 1 ] ) != SLASH )
  218. #endif /* __AMIGA__ || __ARC__ || __ATARI__ || __MAC__ || __MSDOS__ || __OS2__ || __VMS__ */
  219.                         {
  220.                         strcat( basePath, SLASH_STR );
  221.                         length++;
  222.                         }
  223.                     basePathLen = length;
  224.  
  225.                     /* Make sure we don't try and use wildcards in the path */
  226.                     if( strHasWildcards( basePath ) )
  227.                         error( CANNOT_USE_WILDCARDS_s, basePath );
  228.                     break;
  229.  
  230.                 case 'C':
  231.                     flags |= CRYPT;
  232.  
  233.                     ch = *strPtr++;
  234.                     switch( toupper( ch ) )
  235.                         {
  236.                         case 'A':
  237.                             cryptFlags |= CRYPT_CKE_ALL;
  238.                             break;
  239.  
  240.                         case 'I':
  241.                             cryptFlags |= CRYPT_CKE;
  242.                             break;
  243.  
  244.                         case 'P':
  245.                             ch = *strPtr++;
  246.                             ch = toupper( ch );
  247.                             if( ch == 'S' )
  248.                                 {
  249.                                 cryptFlags |= CRYPT_SEC | CRYPT_PKE_ALL;
  250.                                 secUserID = strPtr;
  251.                                 }
  252.                             else
  253.                                 {
  254.                                 if( ch == 'A' )
  255.                                     cryptFlags |= CRYPT_PKE_ALL;
  256.                                 else
  257.                                     cryptFlags |= CRYPT_PKE;
  258.                                 mainUserID = strPtr;
  259.                                 }
  260.  
  261.                             /* Check for existence of userID, and skip it */
  262.                             if( !*strPtr )
  263.                                 error( MISSING_USERID );
  264.                             while( *strPtr )
  265.                                 strPtr++;        /* Skip to end of arg */
  266.                             break;
  267.  
  268.                         case 'S':
  269.                             cryptFlags |= CRYPT_SEC | CRYPT_CKE_ALL;
  270.                             break;
  271.  
  272.                         default:
  273.                             cryptFlags |= CRYPT_CKE_ALL;
  274.                             strPtr--;
  275.                         }
  276.  
  277.                     /* Make sure we're not trying to encrypt using two
  278.                        methods */
  279.                     ch = cryptFlags & ( CRYPT_CKE | CRYPT_PKE | CRYPT_CKE_ALL | CRYPT_PKE_ALL );
  280.                     if( ch != CRYPT_CKE && ch != CRYPT_PKE && \
  281.                         ch != CRYPT_CKE_ALL && ch != CRYPT_PKE_ALL )
  282.                         error( CANNOT_USE_BOTH_CKE_PKE );
  283.                     break;
  284.  
  285.                 case 'D':
  286.                     ch = *strPtr++;
  287.                     switch( toupper( ch ) )
  288.                         {
  289.                         case 'A':
  290.                             dirFlags |= DIR_ALLPATHS;
  291.                             flags |= STORE_PATH;
  292.                             break;
  293.  
  294.                         case 'C':
  295.                             dirFlags |= DIR_CONTAIN;
  296.                             break;
  297.  
  298.                         case 'M':
  299.                             dirFlags |= DIR_MKDIR;
  300.                             break;
  301.  
  302.                         case 'N':
  303.                             dirFlags |= DIR_NOCREATE;
  304.                             flags |= STORE_PATH;
  305.                             break;
  306.  
  307.                         case 'R':
  308.                             dirFlags |= DIR_RMDIR;
  309.                             break;
  310.  
  311.                         case 'V':
  312.                             dirFlags |= DIR_MVDIR;
  313.                             break;
  314.  
  315.                         default:
  316.                             flags |= STORE_PATH;
  317.                             strPtr--;
  318.                         }
  319.                     break;
  320.  
  321.                 case 'E':
  322.                     flags |= ERROR_RECOVER;
  323.                     break;
  324.  
  325.                 case 'F':
  326.                     /* Only apply the move command if it would make sense
  327.                        (protect the user from performing a move on Display
  328.                        or Test) */
  329.                     if( choice == ADD || choice == FRESHEN || choice == EXTRACT || \
  330.                         choice == REPLACE || choice == UPDATE )
  331.                         flags |= MOVE_FILES;
  332.                     break;
  333.  
  334.                 case 'I':
  335.                     flags |= INTERACTIVE;
  336.                     break;
  337.  
  338.                 case 'K':
  339.                     flags |= OVERWRITE_SRC;
  340.                     if( choice == FRESHEN || choice == REPLACE || choice == UPDATE )
  341.                         error( CANNOT_CHANGE_DEL_ARCH );
  342.                     break;
  343.  
  344.                 case 'L':
  345.                     ch = *strPtr++;
  346.                     if( toupper( ch ) == 'I' )
  347.                         cryptFlags |= CRYPT_SIGN;
  348.                     else
  349.                         {
  350.                         strPtr--;    /* Back up arg.pointer */
  351.                         cryptFlags |= CRYPT_SIGN_ALL;
  352.                         }
  353.                     signerID = strPtr;    /* Point to ID of signer */
  354.  
  355.                     /* Check for existence of userID, and skip it */
  356.                     if( !*strPtr )
  357.                         error( MISSING_USERID );
  358.                     while( *strPtr )
  359.                         strPtr++;        /* Skip to end of arg */
  360.                     break;
  361.  
  362.                 case 'M':
  363.                     flags |= MULTIPART_ARCH;
  364.                     if( choice == DELETE || choice == FRESHEN || \
  365.                         choice == REPLACE || choice == UPDATE || \
  366.                         ( choice == EXTRACT && ( flags & MOVE_FILES ) ) )
  367.                         error( CANNOT_CHANGE_MULTIPART_ARCH );
  368.                     if( choice == ADD )
  369.                         multipartFlags |= MULTIPART_WRITE;
  370.                     break;
  371.  
  372.                 case 'N':
  373. #ifdef __MSDOS__
  374.                     ndoc( &strPtr );
  375. #endif /* __MSDOS__ */
  376.                     break;
  377.  
  378.                 case 'O':
  379.                     ch = *strPtr++;
  380.                     switch( toupper( ch ) )
  381.                         {
  382.                         case 'A':
  383.                             overwriteFlags |= OVERWRITE_ALL;
  384.                             break;
  385.  
  386.                         case 'N':
  387.                             overwriteFlags |= OVERWRITE_NONE;
  388.                             break;
  389.  
  390.                         case 'P':
  391.                             overwriteFlags |= OVERWRITE_PROMPT;
  392.                             break;
  393.  
  394.                         case 'S':
  395.                             overwriteFlags |= OVERWRITE_SMART;
  396.                             break;
  397.  
  398.                         default:
  399.                             error( UNKNOWN_OVERWRITE_OPTION, *--strPtr  );
  400.                         }
  401.                     break;
  402.  
  403.                 case 'R':
  404.                     flags |= RECURSE_SUBDIR;
  405.                     break;
  406.  
  407.                 case 'S':
  408.                     /* Stuart if you fclose( STDOUT ) to implement this I'll
  409.                        dump ten thousand frogs on you */
  410.                     flags |= STEALTH_MODE;
  411.                     break;
  412.  
  413.                 case 'T':
  414.                     flags |= TOUCH_FILES;
  415.                     break;
  416.  
  417.                 case 'U':
  418.                     flags |= BLOCK_MODE;
  419.                     break;
  420.  
  421.                 case 'V':
  422.                     ch = *strPtr++;
  423.                     switch( toupper( ch ) )
  424.                         {
  425.                         case 'D':
  426.                             viewFlags |= VIEW_DIRS;
  427.                             break;
  428.  
  429.                         case 'F':
  430.                             viewFlags |= VIEW_FILES;
  431.                             break;
  432.  
  433.                         case 'S':
  434.                             viewFlags |= VIEW_SORTED;
  435.                             break;
  436.  
  437.                         default:
  438.                             error( UNKNOWN_VIEW_OPTION, *--strPtr  );
  439.                         }
  440.                     break;
  441.  
  442.                 case 'W':
  443.                     flags |= ARCH_COMMENT;
  444.                     ch = *strPtr++;
  445.                     switch( toupper( ch ) )
  446.                         {
  447.                         case 'A':
  448.                             /* ANSI text comment */
  449.                             commentType = TYPE_COMMENT_ANSI;
  450.                             break;
  451.  
  452.                         case 'G':
  453.                             /* GIF graphics comment */
  454.                             commentType = TYPE_COMMENT_GIF;
  455.                             break;
  456.  
  457.                         default:
  458.                             /* Default: Text comment */
  459.                             commentType = TYPE_COMMENT_TEXT;
  460.                             strPtr--;    /* Correct strPtr value */
  461.                         }
  462.                     break;
  463.  
  464.                 case 'X':
  465.                     /* Only apply outupt translation if it would make sense */
  466.                     if( choice == EXTRACT || choice == DISPLAY )
  467.                         flags |= XLATE_OUTPUT;
  468.  
  469.                     /* Determine which kind of translation is required */
  470.                     ch = *strPtr++;
  471.                     switch( toupper( ch ) )
  472.                         {
  473.                         case 'A':
  474.                             xlateFlags |= XLATE_EOL;
  475.                             lineEndChar = '\0';
  476.                             break;
  477.  
  478. #if !defined( __ATARI__ ) && !defined( __MSDOS__ ) && !defined( __OS2__ )
  479.                         case 'C':
  480.                             xlateFlags |= XLATE_EOL;
  481.                             lineEndChar = '\r' | 0x80;
  482.                             break;
  483. #endif /* !( __ATARI__ || __MSDOS__ || __OS2__ ) */
  484.  
  485.                         case 'E':
  486.                             xlateFlags |= XLATE_EBCDIC;
  487.                             break;
  488.  
  489. #if !defined( __AMIGA__ ) && !defined( __ARC__ ) && !defined( __UNIX__ )
  490.                         case 'L':
  491.                             xlateFlags |= XLATE_EOL;
  492.                             lineEndChar = '\n';
  493.                             break;
  494. #endif /* !( __AMIGA__ || __ARC__ || __UNIX__ ) */
  495.  
  496.                         case 'P':
  497.                             xlateFlags |= XLATE_PRIME;
  498.                             break;
  499.  
  500. #ifndef __MAC__
  501.                         case 'R':
  502.                             xlateFlags |= XLATE_EOL;
  503.                             lineEndChar = '\r';
  504.                             break;
  505. #endif /* !__MAC__ */
  506.  
  507.                         case 'S':
  508.                             xlateFlags = XLATE_SMART;
  509.                             break;
  510.  
  511.                         case 'X':
  512.                             /* Get line-end-char in hex */
  513.                             xlateFlags |= XLATE_EOL;
  514.                             lineEndChar = getHexByte( &strPtr );
  515.                             break;
  516.  
  517.                         default:
  518.                             /* Default: Smart translate - ignore
  519.                                lineEndChar setting */
  520.                             xlateFlags = XLATE_SMART;
  521.                             strPtr--;    /* Correct strPtr value */
  522.                         }
  523.  
  524.                     /* Set up the translation system if necessary */
  525.                     initTranslationSystem( lineEndChar );
  526.  
  527.                     break;
  528.  
  529.                 case 'Z':
  530. #if defined( __MSDOS__ )
  531.                     if( toupper( *strPtr ) == 'S' )
  532.                         /* Check for device filenames on extract */
  533.                         sysSpecFlags |= SYSPEC_CHECKSAFE;
  534.                     else
  535.                         error( UNKNOWN_OPTION, *--strPtr );
  536.  
  537.                     strPtr++;            /* Skip arg */
  538. #elif defined( __AMIGA__ ) || defined( __OS2__ )
  539.                     if( matchString( strPtr, "lower", NO_WILDCARDS ) )
  540.                         {
  541.                         /* Force lower case on file and dir names if it
  542.                            would make sense */
  543.                         if( choice == VIEW || choice == EXTRACT || \
  544.                             choice == TEST || choice == DISPLAY )
  545.                             sysSpecFlags |= SYSPEC_FORCELOWER;
  546.                         }
  547.  
  548.                     while( *strPtr )
  549.                         strPtr++;        /* Skip to end of arg */
  550. #elif defined( __ARC__ )
  551.                     if( matchString( strPtr, "invert", NO_WILDCARDS ) )
  552.                         {
  553.                         /* Invert filename extensions into directories if it
  554.                            would make sense */
  555.                         if( choice == EXTRACT )
  556.                             sysSpecFlags |= SYSPEC_INVERTDIR;
  557.                         }
  558.                     else
  559.                         if( matchString( strPtr, "lower", NO_WILDCARDS ) )
  560.                             {
  561.                             /* Force lower case on file and dir names if it
  562.                                would make sense */
  563.                             if( choice == VIEW || choice == EXTRACT || \
  564.                                 choice == TEST || choice == DISPLAY )
  565.                                 sysSpecFlags |= SYSPEC_FORCELOWER;
  566.                             }
  567.                         else
  568.                             if( matchString( strPtr, "type", NO_WILDCARDS ) )
  569.                                 /* Add file-type association data */
  570.                                 addTypeAssociation( strPtr + 5 );
  571.                             else
  572.                                 error( UNKNOWN_OPTION, *--strPtr );
  573.  
  574.                     while( *strPtr )
  575.                         strPtr++;        /* Skip to end of arg */
  576. #elif defined( __IIGS__ ) || defined( __MAC__ )
  577.                     if( matchString( strPtr, "lower", NO_WILDCARDS ) )
  578.                         {
  579.                         /* Force lower case on file and dir names if it
  580.                            would make sense */
  581.                         if( choice == VIEW || choice == EXTRACT || \
  582.                             choice == TEST || choice == DISPLAY )
  583.                             sysSpecFlags |= SYSPEC_FORCELOWER;
  584.                         }
  585.                     else
  586.                         if( matchString( strPtr, "type", NO_WILDCARDS ) )
  587.                             /* Add file-type association data */
  588.                             addTypeAssociation( strPtr + 5 );
  589.                         else
  590.                             error( UNKNOWN_OPTION, *--strPtr );
  591.  
  592.                     while( *strPtr )
  593.                         strPtr++;        /* Skip to end of arg */
  594. #elif defined( __UNIX__ )
  595.                     if( matchString( strPtr, "lower", NO_WILDCARDS ) )
  596.                         {
  597.                         /* Force lower case on file and dir names if it
  598.                            would make sense */
  599.                         if( choice == VIEW || choice == EXTRACT || \
  600.                             choice == TEST || choice == DISPLAY )
  601.                             sysSpecFlags |= SYSPEC_FORCELOWER;
  602.                         }
  603.                     else
  604.                         if( matchString( strPtr, "noumask", NO_WILDCARDS ) )
  605.                             /* Ignore umask for file and dir attributes */
  606.                             sysSpecFlags |= SYSPEC_NOUMASK;
  607.                         else
  608.                             if( matchString( strPtr, "device", NO_WILDCARDS ) )
  609.                                 {
  610.                                 /* Treat archive name as device for multipart
  611.                                    archive to device */
  612.                                 sysSpecFlags |= SYSPEC_DEVICE;
  613.                                 flags |= OVERWRITE_SRC;
  614.                                 }
  615.                             else
  616.                                 error( UNKNOWN_OPTION, *--strPtr );
  617.  
  618.                     while( *strPtr )
  619.                         strPtr++;        /* Skip to end of arg */
  620. #elif defined( __VMS__ )
  621.                     if( matchString( strPtr, "rsx", NO_WILDCARDS ) )
  622.                         /* Translate file/dir names to RSX-11 type format */
  623.                         sysSpecFlags |= SYSPEC_RSX11;
  624.                     else
  625.                         error( UNKNOWN_OPTION, *--strPtr );
  626.  
  627.                     while( *strPtr )
  628.                         strPtr++;        /* Skip to end of arg */
  629. #else
  630.                     error( LONG_ARG_NOT_SUPPORTED );
  631. #endif /* Various system-specific options */
  632.                     break;
  633.  
  634.                 default:
  635.                     error( UNKNOWN_OPTION, *--strPtr );
  636.                 }
  637.             }
  638.         ( *count )++;
  639.         }
  640.  
  641.     /* If we're performing public-key encryption with a secondary userID,
  642.        make sure the user has also entered a primary userID */
  643.     if( !( cryptFlags ^ ( CRYPT_SEC | CRYPT_PKE_ALL ) ) && mainUserID == NULL )
  644.         error( MISSING_USERID );
  645.  
  646. #ifdef __OS2__
  647.     /* Set the flag which controls filename truncation depending on whether
  648.        we are extracting to an HPFS or FAT filesystem */
  649.     destIsHPFS = queryFilesystemType( basePath );
  650. #endif /* __OS2__ */
  651. #ifdef __MAC__
  652.     /* Remember the vRefNum for the path from/to which we are munging files */
  653.     setVolumeRef( basePath, FILE_PATH );
  654. #endif /* __MAC__ */
  655.     }
  656.  
  657. /****************************************************************************
  658. *                                                                            *
  659. *                                Main Program Code                            *
  660. *                                                                            *
  661. ****************************************************************************/
  662.  
  663. #if !defined( __IIGS__ ) && !defined( __MAC__ ) && !defined( __MSDOS__ )
  664.  
  665. /* Handle program interrupt */
  666.  
  667. #include <signal.h>
  668.  
  669. static void progBreak( int dummyValue )
  670.     {
  671.     dummyValue = dummyValue;    /* Get rid of used but not defined warning */
  672.     error( STOPPED_AT_USER_REQUEST );
  673.     }
  674. #endif /* !( __IIGS__ || __MAC__ || __MSDOS__ ) */
  675.  
  676. #ifdef __MAC__                    /* Needed for command-line processing */
  677.   #include <console.h>
  678. #endif /* __MAC__ */
  679.  
  680. /* The main program */
  681.  
  682. int main( int argc, char *argv[] )
  683.     {
  684.     int no, count = 1, lastSlash;
  685.     FILEINFO archiveInfo;
  686.     char archivePath[ MAX_PATH ], fileCode[ MATCH_DEST_LEN ], ch;
  687.     BOOLEAN createNew, nothingDone = TRUE, hasFileSpec = FALSE;
  688.     BOOLEAN gotPassword = FALSE, hasWildCards;
  689.  
  690. #ifdef __MAC__
  691.     /* Get command-line parameters */
  692.     argc = ccommand( &argv );
  693. #endif /* __MAC__ */
  694.  
  695.     /* Spew forth some propaganda */
  696.     showTitle();
  697.  
  698. #if !defined( __IIGS__ ) && !defined( __MAC__ ) && !defined( __MSDOS__ )
  699.     /* Trap program break */
  700.   #ifdef __UNIX__
  701.     if( signal( SIGINT, SIG_IGN ) == SIG_IGN )
  702.         /* If we're running in the background, turn on stealth mode so we
  703.            don't swamp the (l)user with noise */
  704.         flags |= STEALTH_MODE;
  705.     else
  706.   #endif /* __UNIX__ */
  707.     signal( SIGINT, progBreak );
  708. #endif /* !( __IIGS__ || __MAC__ || __MSDOS__ ) */
  709.  
  710.     /* Perform general initialization */
  711. #if defined( __MSDOS__ )
  712.     initMem();        /* Init mem.mgr - must come before all other inits */
  713. #endif /* __MSDOS__ */
  714.     initFastIO();
  715. #ifndef __OS2__
  716.     initExtraInfo();
  717. #endif /* __OS2__ */
  718.     setDateFormat();
  719.     getScreenSize();
  720.  
  721.     /* Only initialise the compressor/decompressor if we have to.
  722.        Unfortunately we need to initialise the decompressor for the VIEW
  723.        command since there may be compressed archive comments in the data */
  724.     if( ( argc > 1 ) && ( ch = toupper( *argv[ 1 ] ) ) != DELETE )
  725.         /* Only allocate the memory for the compressor if we have to */
  726.         initPack( ch != EXTRACT && ch != TEST && ch != DISPLAY );
  727.  
  728.     initArcDir();    /* Must be last init in MSDOS version */
  729.  
  730.     /* If there are not enough command-line args, exit with a help message */
  731.     if( argc < 3 )
  732.         showHelp();
  733.  
  734.     /* First process command */
  735.     doCommand( argv[ 1 ] );
  736.     count++;
  737.     doArg( argv, &count );
  738.     createNew = ( choice == ADD && ( flags & OVERWRITE_SRC ) ) ? TRUE : FALSE;
  739.                                         /* Common subexpr.elimination */
  740.  
  741.     /* Allow room in path for '.xxx\0' suffix */
  742.     if( strlen( argv[ count ] ) > MAX_PATH - 5 )
  743.         error( PATH_s_TOO_LONG, argv[ count ] );
  744.     else
  745.         strcpy( archiveFileName, argv[ count++ ] );
  746.  
  747.     /* Extract the pathname and convert it into an OS-compatible format */
  748.     lastSlash = extractPath( archiveFileName, archivePath );
  749. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
  750.     archiveDrive = ( archiveFileName[ 1 ] == ':' ) ? toupper( *archiveFileName ) - 'A' + 1 : 0;
  751. #endif /* __ATARI__ || __MSDOS__ || __OS2__ */
  752.  
  753.     /* Either append archive file suffix to the filespec or force the
  754.        existing suffix to HPAK_MATCH_EXT, and point the variable no to the
  755.        end of the filename component */
  756.     for( no = strlen( archiveFileName ); \
  757.          no >= lastSlash && archiveFileName[ no ] != '.';
  758.          no-- );
  759. #ifdef __UNIX__
  760.     if( !( sysSpecFlags & SYSPEC_DEVICE ) )
  761.         /* Only force the HPACK extension if it's a normal file */
  762. #endif /* __UNIX__ */
  763.     if( archiveFileName[ no ] != '.' )
  764.         {
  765.         no = strlen( archiveFileName );
  766.         strcat( archiveFileName, HPAK_MATCH_EXT );
  767.         }
  768.     else
  769.         strcpy( archiveFileName + no, HPAK_MATCH_EXT );
  770.  
  771. #ifdef __OS2__
  772.     /* Make sure we get the case-mangling right */
  773.     isHPFS = queryFilesystemType( archiveFileName );
  774. #endif /* __OS2__ */
  775. #ifdef __MAC__
  776.     /* Remember the vRefNum for the archive path.  In addition we strip off
  777.        the volume name, since if we're creating a multidisk archive the
  778.        volume name may change with each disk */
  779.     setVolumeRef( archiveFileName, ARCHIVE_PATH );
  780.     no -= stripVolumeName( archivePath );
  781.     lastSlash -= stripVolumeName( archiveFileName );
  782. #endif /* __MAC__ */
  783.  
  784.     /* Compile the filespec into a form acceptable by the wildcard-matching
  785.        finite-state machine */
  786.     compileString( archiveFileName + lastSlash, fileCode );
  787.  
  788.     /* Now add names of files to be processed to the fileName list */
  789.     while( count < argc )
  790.         {
  791.         if( *argv[ count ] == '@' )
  792.             {
  793.             /* Assemble the listFile name + path into the dirBuffer (we can't
  794.                use the mrglBuffer since processListFile() ovrewrites it) */
  795.             strcpy( ( char * ) dirBuffer, argv[ count++ ] + 1 );
  796.             lastSlash = extractPath( ( char * ) dirBuffer, ( char * ) dirBuffer + 80 );
  797.             compileString( ( char * ) dirBuffer + lastSlash, ( char * ) dirBuffer + 80 );
  798.             hasWildCards = strHasWildcards( ( char * ) dirBuffer + 80 );
  799. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __MAC__ ) || defined( __OS2__ )
  800.             if( lastSlash && ( ch = dirBuffer[ lastSlash - 1 ] ) != SLASH && \
  801.                                                               ch != ':' )
  802. #else
  803.             if( lastSlash && ( ch = dirBuffer[ lastSlash - 1 ] ) != SLASH )
  804. #endif /* __ATARI__ || __MAC__ || __MSDOS__ || __OS2__ */
  805.                 /* Add a slash if necessary */
  806.                 dirBuffer[ lastSlash - 1 ] = SLASH;
  807.             strcpy( ( char * ) dirBuffer + lastSlash, MATCH_ALL );
  808.  
  809.             /* Check each file in the directory, passing those that match to
  810.                processListFile() */
  811.             if( findFirst( ( char * ) dirBuffer, FILES, &archiveInfo ) )
  812.                 {
  813.                 do
  814.                     {
  815.                     strcpy( ( char * ) dirBuffer + lastSlash, archiveInfo.fName );
  816.                     if( matchString( ( char * ) dirBuffer + 80, archiveInfo.fName, hasWildCards ) )
  817.                         processListFile( ( char * ) dirBuffer );
  818.                     }
  819.                 while( findNext( &archiveInfo ) );
  820.                 findEnd( &archiveInfo );
  821.                 }
  822.             }
  823.         else
  824.             addFilespec( ( char * ) argv[ count++ ] );
  825.         hasFileSpec = TRUE;
  826.         }
  827.  
  828.     /* Default is all files if no name is given */
  829.     if( !hasFileSpec )
  830.         addFilespec( WILD_MATCH_ALL );
  831.  
  832.     /* See if we can find a matching archive.  The only case where a non-
  833.        match is not an error is if we are using the ADD command:  In this
  834.        case we create a new archive */
  835. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
  836.     if( lastSlash && ( ch = archivePath[ lastSlash - 1 ] ) != SLASH && \
  837.                                                         ch != ':' )
  838. #else
  839.     if( lastSlash && ( ch = archivePath[ lastSlash - 1 ] ) != SLASH )
  840. #endif /* __ATARI__ || __MSDOS__ || __OS2__ */
  841.         /* Add a slash if necessary */
  842.         archivePath[ lastSlash - 1 ] = SLASH;
  843.     strcpy( archivePath + lastSlash, MATCH_ARCHIVE );
  844.     if( !findFirst( archivePath, FILES, &archiveInfo ) )
  845.         if( choice == ADD && !hasWildcards( archiveFileName + lastSlash, no - lastSlash ) )
  846.             /* No existing archive found, force the creation of a new one */
  847.             createNew = TRUE;
  848.         else
  849.             error( NO_ARCHIVES );
  850.  
  851.     /* Set up the encryption system */
  852.     initCrypt();
  853.  
  854.     /* Now process each archive which matches the given filespec */
  855. again:
  856.     do
  857.         if( createNew || matchString( fileCode, archiveInfo.fName, TRUE ) )
  858.             {
  859.             if( createNew )
  860.                 {
  861. #ifdef __UNIX__
  862.                 if( !( sysSpecFlags & SYSPEC_DEVICE ) )
  863.                     /* Only force the HPACK extension if it's a normal file */
  864. #endif /* __UNIX__ */
  865.                 /* Set the extension to the proper form */
  866.                 strcpy( archiveFileName + no, HPAK_EXT );
  867.                 strcpy( errorFileName, archiveFileName );
  868.                 }
  869.             else
  870.                 {
  871.                 /* Set archivePath as well as archiveFileName to the archive's
  872.                    name, since when processing multiple archives archiveFileName
  873.                    will be stomped */
  874.                 strcpy( archivePath + lastSlash, archiveInfo.fName );
  875.                 strcpy( archiveFileName, archivePath );
  876.                 if( addArchiveName( archiveInfo.fName ) )
  877.                     /* Make sure we don't try to process the same archive
  878.                        twice (see the comment for addArchiveName) */
  879.                     continue;
  880.                 }
  881.  
  882.             hprintfs( MESG_ARCHIVE_IS_s, archiveFileName );
  883.  
  884.             /* Reset error stats and arcdir system */
  885.             archiveFD = errorFD = dirFileFD = secFileFD = IO_ERROR;
  886.             oldArcEnd = 0L;
  887.             resetArcDir();
  888.             overWriteEntry = FALSE;
  889.             if( flags & BLOCK_MODE )
  890.                 firstFile = TRUE;
  891.  
  892.             /* Open archive file with various types of mungeing depending on the
  893.                command type */
  894.             if( choice == ADD || choice == UPDATE )
  895.                 {
  896.                 /* Create a new archive if none exists or overwrite an existing
  897.                    one if asked for */
  898.                 if( createNew )
  899.                     {
  900.                     errorFD = archiveFD = hcreat( archiveFileName, CREAT_ATTR );
  901.                     setOutputFD( archiveFD );
  902.                     }
  903.                 else
  904.                     if( ( archiveFD = hopen( archiveFileName, O_RDWR | S_DENYRDWR | A_SEQ ) ) != IO_ERROR )
  905.                         {
  906.                         setInputFD( archiveFD );
  907.                         setOutputFD( archiveFD );
  908.                         readArcDir( SAVE_DIR_DATA );
  909.  
  910.                         /* If we are adding to an existing archive and run out
  911.                            of disk space, we must cut back to the size of the
  912.                            old archive.  We do this by remembering the old state
  913.                            of the archive and restoring it to this state if
  914.                            necessary */
  915.                         if( fileHdrStartPtr != NULL )
  916.                             /* Only set oldArcEnd if there are files in the archive */
  917.                             oldArcEnd = fileHdrCurrPtr->offset + fileHdrCurrPtr->data.dataLen + \
  918.                                         fileHdrCurrPtr->data.auxDataLen;
  919.                         getArcdirState( ( FILEHDRLIST ** ) &oldHdrlistEnd, &oldDirEnd );
  920.  
  921.                         /* Move past existing data */
  922.                         hlseek( archiveFD, oldArcEnd + HPACK_ID_SIZE, SEEK_SET );
  923.                         }
  924.                 }
  925.             else
  926.                 {
  927.                 /* Try to open the archive for read/write (in case we need to
  928.                    truncate X/Ymodem padding bytes.  If that fails, open it
  929.                    for read-only */
  930.                 if( ( archiveFD = hopen( archiveFileName, O_RDWR | S_DENYWR | A_RANDSEQ ) ) == IO_ERROR )
  931.                     archiveFD = hopen( archiveFileName, O_RDONLY | S_DENYWR | A_RANDSEQ );
  932.                 setInputFD( archiveFD );
  933.                 if( archiveFD != IO_ERROR )
  934.                     readArcDir( choice != VIEW && choice != EXTRACT && \
  935.                                 choice != TEST && choice != DISPLAY  );
  936.  
  937.                 /* The password will have been obtained as part the process
  938.                    of reading the archive directory */
  939.                 gotPassword = TRUE;
  940.                 }
  941.  
  942.             /* Make sure the open was successful */
  943.             if( archiveFD == IO_ERROR )
  944.                 error( CANNOT_OPEN_ARCHFILE, archiveFileName );
  945.  
  946.             /* We've found an archive to ADD things to, so signal the fact
  947.                that we don't need to make a second pass with the createNew
  948.                flag set */
  949.             nothingDone = FALSE;
  950.  
  951.             /* Set up the password(s) if necessary */
  952.             if( !gotPassword && ( cryptFlags & ( CRYPT_CKE | CRYPT_CKE_ALL ) ) )
  953.                 {
  954.                 initPassword( MAIN_KEY );
  955.                 if( cryptFlags & CRYPT_SEC )
  956.                     initPassword( SECONDARY_KEY );
  957.  
  958.                 /* Flag the fact that we no longer need to get the password
  959.                    later on if there are more archives */
  960.                 gotPassword = TRUE;
  961.                 }
  962.  
  963.             /* Now munge files to/from archive */
  964.             handleArchive();
  965.  
  966.             /* The UPDATE command is just a combination of the ADD and FRESHEN
  967.                commands.  We handle it by first adding new files in one pass
  968.                (but not complaining when we strike duplicates like ADD does),
  969.                and then using the freshen command to update duplicates in a
  970.                second pass.  This leads to a slight problem in that when files
  971.                are added they will then subsequently match on the freshen pass;
  972.                hopefully the extra overhead from checking whether they should
  973.                be freshened will not be too great */
  974.             if( choice == UPDATE )
  975.                 {
  976.                 choice = FRESHEN;
  977.                 oldArcEnd = 0L;    /* Make sure we don't try any ADD-style recovery
  978.                                    since errorFD is now the temp file FD */
  979.                 vlseek( 0L, SEEK_SET );    /* Go back to start of archive */
  980.                 handleArchive();
  981.                 }
  982.  
  983.             /* The EXTRACT command with MOVE_FILES option is just a
  984.                combination of the standard EXTRACT and DELETE commands.  We
  985.                handle this by making a second pass which deletes the files.
  986.                This could be done in one step by combining the EXTRACT and
  987.                DELETE, but doing it this way is much easier since the two
  988.                normally involve several mutually exclusive alternatives */
  989.             if( choice == EXTRACT && ( flags & MOVE_FILES ) )
  990.                 {
  991.                 choice = DELETE;
  992.                 oldArcEnd = 0L;            /* Don't try any recovery */
  993.                 vlseek( 0L, SEEK_SET );    /* Go back to start of archive */
  994.                 handleArchive();
  995.                 }
  996.  
  997.             /* Perform cleanup functions for this file */
  998.             if( choice != DELETE && choice != FRESHEN && choice != REPLACE && \
  999.                 !( choice == EXTRACT && ( flags & MOVE_FILES ) ) )
  1000.                 /* If DELETE, FRESHEN, or REPLACE, archive file is already closed */
  1001.                 {
  1002.                 hclose( archiveFD );
  1003.                 archiveFD = IO_ERROR;    /* Mark it as invalid */
  1004.                 }
  1005.  
  1006.             /* Perform any updating of extra file information on the archive
  1007.                if we've changed it, unless it's a multipart archive which
  1008.                leads to all sorts of complications */
  1009.             if( archiveChanged && !( flags & MULTIPART_ARCH ) && \
  1010.                 !( choice == VIEW || choice == TEST || choice == EXTRACT || choice == DISPLAY ) )
  1011.                 setExtraInfo( archiveFileName );
  1012.  
  1013.             /* Now that we've finished all processing, delete any files we've
  1014.                added if the MOVE_FILES option was used */
  1015.             if( archiveChanged && ( flags & MOVE_FILES ) )
  1016.                 wipeFilePaths();
  1017.  
  1018. #if defined( __MSDOS__ )
  1019.             /* Reset arcDir filesystem in memory */
  1020.             resetArcDirMem();
  1021. #endif /* __MSDOS__ */
  1022.  
  1023.             /* Only go through the loop once if we are either creating a new
  1024.                archive or processing a multipart archive */
  1025.             if( createNew || flags & MULTIPART_ARCH )
  1026.                 break;
  1027.             }
  1028.     while( findNext( &archiveInfo ) );
  1029.  
  1030.     /* There were no files found to ADD to, so we execute the above loop one
  1031.        more time and create a new archive */
  1032.     if( choice == ADD && nothingDone )
  1033.         {
  1034.         createNew = TRUE;
  1035.         goto again;
  1036.         }
  1037.  
  1038.     /* Finish findFirst() functions */
  1039.     findEnd( &archiveInfo );
  1040.  
  1041.     /* Complain if we didn't end up doing anything */
  1042.     if( !archiveChanged )
  1043.         if( choice == FRESHEN )
  1044.             {
  1045.             /* If we were freshening an archive then the nonexistance of
  1046.                files to change isn't necessarily a problem */
  1047.             hputs( MESG_ARCH_IS_UPTODATE );
  1048.             closeFiles();
  1049.             }
  1050.         else
  1051.             /* There was nothing to do to the archive, treat as an error
  1052.                condition */
  1053.             if( nothingDone )
  1054.                 /* Couldn't find a matching archive */
  1055.                 error( NO_ARCHIVES );
  1056.             else
  1057.                 if( choice == ADD || choice == REPLACE )
  1058.                     /* Couldn't find a matching file to add */
  1059.                     error( NO_FILES_ON_DISK );
  1060.                 else
  1061.                     /* Couldn't find a matching file in the archive */
  1062.                     error( NO_FILES_IN_ARCHIVE );
  1063.  
  1064.     /* Clean up before exiting */
  1065.     if( choice == VIEW )
  1066.         showTotals();
  1067.     endCrypt();
  1068. #if defined( __MSDOS__ )
  1069.     endMem();        /* The mem.mgr.takes care of all memory freeing */
  1070. #else
  1071.     if( choice != DELETE )
  1072.         endPack();
  1073.     endArcDir();
  1074.     endExtraInfo();
  1075.     endFastIO();
  1076.     freeFilespecs();
  1077.     freeArchiveNames();
  1078. #endif /* __MSDOS__ */
  1079.  
  1080.     /* Obesa Cantavit */
  1081.     hputs( MESG_DONE );
  1082. #ifdef __VMS__
  1083.     return( translateVMSretVal( OK ) );
  1084. #else
  1085.     return( OK );
  1086. #endif /* __VMS__ */
  1087.     }
  1088.